package com.yunxi.service.localService.impl.finance;

import com.alibaba.fastjson.JSONObject;
import com.yunxi.core.service.ServiceImplPlus;
import com.yunxi.core.web.ApiResult;
import com.yunxi.core.web.LoginInfo;
import com.yunxi.core.web.ResponseUtil;
import com.yunxi.dao.finance.FinanceProductMapper;
import com.yunxi.dealer.pojo.PartnerVO;
import com.yunxi.finance.pojo.FinanceInstitutionVO;
import com.yunxi.finance.pojo.FinanceProductCalculateResultVO;
import com.yunxi.finance.pojo.FinanceProductCalculateVO;
import com.yunxi.finance.pojo.FinanceProductVO;
import com.yunxi.model.finance.FinanceProduct;
import com.yunxi.service.localService.finance.FinanceProductService;
import org.apache.poi.ss.formula.functions.FinanceLib;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 金融产品维护 服务实现类
 * </p>
 *
 * @author XUQI
 * @since 2019-12-02
 */
@Service
public class FinanceProductServiceImpl extends ServiceImplPlus<FinanceProductMapper, FinanceProduct> implements
    FinanceProductService {

    private static final Logger logger = LoggerFactory.getLogger(FinanceProductServiceImpl.class);


    /**
     * 金融产品保存方法
     *
     * @param financeProductVO 金融产品VO
     */
    @Override
    public ApiResult saveOrUpdate(FinanceProductVO financeProductVO) {
        FinanceProduct financeProduct = new FinanceProduct();
        BeanUtils.copyProperties(financeProductVO, financeProduct);
        super.saveOrUpdate(financeProduct);
        return ResponseUtil.ok();
    }


    @Override
    public List<FinanceInstitutionVO> findFinanceInstitutionDropDown() {
        return baseMapper.selectFinanceInstitutionDropDown();
    }

    /**
     * 根据方案类型查询金融产品
     *
     * @param planType 方案类型
     * @return List<FinanceProductVO>
     */
    @Override
    public List<FinanceProductVO> productListByPlanType(String planType, LoginInfo info) {
        PartnerVO partnerVO = JSONObject.parseObject(JSONObject.toJSONString(info.getPartner()), PartnerVO.class);
        String cityStr = null;
        if (partnerVO != null) {
            cityStr = "[\"" + partnerVO.getProvince() + "\",\"" + partnerVO.getCity() + "\"]";
        }
        ///[["11","1101"]]
        Map<String, Object> map = new HashMap<>(1);
        map.put("planType", planType);
        map.put("cityStr", cityStr);
        List<FinanceProductVO> result = baseMapper.queryByList(map);
        result.forEach(financeProductVO -> {
            financeProductVO.setBailList();
            financeProductVO.setBalanceRatioList();
            financeProductVO.setDownPaymentList();
            financeProductVO.setDeadlineList();
        });
        return result;
    }

    /**
     * 金融产品结果计算
     *
     * @param calculateVO 计算参数
     * @return ApiResult
     */
    @Override
    public ApiResult calculate(FinanceProductCalculateVO calculateVO) {
        FinanceProductCalculateResultVO resultVO = new FinanceProductCalculateResultVO();
        try {
            if (calculateVO.getCarPrice() == null || BigDecimal.ZERO.compareTo(calculateVO.getCarPrice()) == 0) {
                logger.debug("车辆金额不能为空");
                return ResponseUtil.fail(-1, "车辆金额不能为空");
            }

            //首付比例+保证金比例≥X
            if (calculateVO.getDownPaymentRatio().add(calculateVO.getBailRatio())
                .compareTo(calculateVO.getCheckValue()) < 0) {
                return ResponseUtil.fail(-1, "首付比例 + 保证金比例应该大于"
                    + calculateVO.getCheckValue().multiply(BigDecimal.valueOf(100)) + "%");
            }

            //1. 计算补贴后车辆总价:补贴后车辆总价=车价+选装包价格
            BigDecimal totalPrice = calculateVO.getCarPrice().add(calculateVO.getPackagePrice());
            resultVO.setTotalPrice(totalPrice);

            //2. 首付款:首付款=首付比例*补贴后车辆总价
            BigDecimal downPaymentPrice = calculateVO.getDownPaymentRatio().multiply(totalPrice);
            resultVO.setDownPaymentPrice(downPaymentPrice);

            //3. 保证金:保证金=保证金比例*补贴后车辆总
            BigDecimal bailPrice = calculateVO.getBailRatio().multiply(totalPrice);
            resultVO.setBailPrice(bailPrice);

            //4.一次性手续费
            BigDecimal oneTimePriceA = calculateVO.getOneTimePriceA().multiply(totalPrice);
            BigDecimal oneTimePriceB = calculateVO.getOneTimePriceB().multiply(totalPrice);
            resultVO.setOneTimeAmountA(oneTimePriceA);
            resultVO.setOneTimeAmountB(oneTimePriceB);

            //5.尾款：尾款=尾款比例*补贴后车辆总价
            BigDecimal balancePrice;
            // 判断取尾款比例还是尾款金额（1:尾款比例 2:尾款金额）
            if (calculateVO.getBalanceShow() == 1) {
                balancePrice = calculateVO.getBalanceRatio().multiply(totalPrice);
            } else {
                balancePrice = calculateVO.getBalanceAmount();
            }
            resultVO.setBalancePrice(balancePrice);

            //6.月供
            // 6.1利率版本：月供 计算公式=abs(pmt(利率/12，期限,（车辆总价-首付款），-尾款，0））
            // 6.2费率版本：月供计算公式=（费率*（补贴后车辆总价-首付款）*期限/12+补贴后车辆总价-首付款-尾款）/期限
            BigDecimal monthPrice;

            //7.客户月供
            // 6.1利率版本：客户月供：在有贴息的情况下，计算公式 =abs(pmt(利率/12，期限,（车辆总价-首付款），-尾款，0））-贴息金额/期限
            // 6.2费率版本：客户月供：在有贴息的情况下，计算公式=（费率*（补贴后车辆总价-首付款）*期限/12-贴息金额+补贴后车辆总价-首付款-尾款）/期限
            BigDecimal customerMonthPrice;

            //贴息金额
            BigDecimal discountAmount = BigDecimal.ZERO;
            // 判断贴息类型 1:显示贴息比例 2:显示贴息金额
            if (calculateVO.getDiscountShow() == 1) {
                if (calculateVO.getDiscountRatio() != null
                    && calculateVO.getDiscountRatio().compareTo(BigDecimal.ZERO) > 0) {
                    discountAmount = calculateVO.getDiscountRatio().multiply(totalPrice);
                }
            } else {
                discountAmount = calculateVO.getDiscountAmount();
            }
            // 判断版本 1:利率 2:费率
            if (calculateVO.getCalculation() == 1) {
                ////月供
                double r = (calculateVO.getRatio().divide(new BigDecimal(12), 10, RoundingMode.HALF_UP)).doubleValue();
                double n = calculateVO.getDeadline();
                double p = totalPrice.subtract(downPaymentPrice).doubleValue();
                double f = balancePrice.negate().doubleValue();
                // PMT公式结果四舍五入保留两位小数再取绝对值
                monthPrice = BigDecimal.valueOf(FinanceLib.pmt(r, n, p, f, false)).setScale(2, RoundingMode.HALF_UP)
                    .abs();

                ////客户月供
                customerMonthPrice = monthPrice.subtract(
                    discountAmount.divide(new BigDecimal(calculateVO.getDeadline()), 2, RoundingMode.HALF_UP));
            } else {
                ////月供
                monthPrice = (calculateVO.getRatio().multiply(totalPrice.subtract(downPaymentPrice))
                    .multiply(BigDecimal.valueOf(calculateVO.getDeadline()))
                    .divide(BigDecimal.valueOf(12), 10, RoundingMode.HALF_UP).add(totalPrice)
                    .subtract(downPaymentPrice).subtract(balancePrice))
                    .divide(BigDecimal.valueOf(calculateVO.getDeadline()), 2, RoundingMode.HALF_UP);

                ////客户月供
                customerMonthPrice = (calculateVO.getRatio().multiply(totalPrice.subtract(downPaymentPrice))
                    .multiply(BigDecimal.valueOf(calculateVO.getDeadline()))
                    .divide(BigDecimal.valueOf(12), 10, RoundingMode.HALF_UP)
                    .subtract(discountAmount).add(totalPrice).subtract(downPaymentPrice).subtract(balancePrice))
                    .divide(BigDecimal.valueOf(calculateVO.getDeadline()), 2, RoundingMode.HALF_UP);

            }
            resultVO.setMonthPrice(monthPrice);
            resultVO.setCustomerMonthPrice(customerMonthPrice);

            //8.费率
            // 8.1利率版本：计算公式=（月供*期限+尾款）/（补贴后车辆总价-首付款）/期限*12
            // 8.2费率版本：显示后台配置项目。
            BigDecimal annualizedRate;

            // 9.客户费率
            // 9.1利率版本：计算公式=（客户月供*期限+尾款）/（补贴后车辆总价-首付款）/期限*12
            // 9.2费率版本：计算公式=（客户月供*期限+尾款+首付款-补贴后车辆总价）/（补贴后车辆总价-首付款）/期限*12
            BigDecimal customerAnnualizedRate;

            // 判断版本 1:利率 2:费率
            if (calculateVO.getCalculation() == 1) {
                // 费率
                annualizedRate = (monthPrice.multiply(BigDecimal.valueOf(calculateVO.getDeadline())).add(balancePrice))
                    .divide(totalPrice.subtract(downPaymentPrice), 10, RoundingMode.HALF_UP)
                    .divide(BigDecimal.valueOf(calculateVO.getDeadline()), 10, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(12)).setScale(4,RoundingMode.HALF_UP);

                //客户费率
                customerAnnualizedRate = (customerMonthPrice.multiply(BigDecimal.valueOf(calculateVO.getDeadline()))
                    .add(balancePrice))
                    .divide(totalPrice.subtract(downPaymentPrice), 10, RoundingMode.HALF_UP)
                    .divide(BigDecimal.valueOf(calculateVO.getDeadline()), 10, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(12)).setScale(4,RoundingMode.HALF_UP);
            } else {
                // 费率
                annualizedRate = calculateVO.getRatio();

                //客户费率
                customerAnnualizedRate = (customerMonthPrice.multiply(BigDecimal.valueOf(calculateVO.getDeadline()))
                    .add(balancePrice).add(downPaymentPrice).subtract(totalPrice))
                    .divide(totalPrice.subtract(downPaymentPrice), 10, RoundingMode.HALF_UP)
                    .divide(BigDecimal.valueOf(calculateVO.getDeadline()), 10, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(12)).setScale(4,RoundingMode.HALF_UP);
            }
            resultVO.setAnnualizedRate(annualizedRate);
            resultVO.setCustomerAnnualizedRate(customerAnnualizedRate);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            return ResponseUtil.fail(-1, e.getMessage());
        }
        return ResponseUtil.ok(resultVO);
    }


    /**
     * 查询配置/选装包价格
     *
     * @param priceType 价格类型（ZVAR：选装包价格-零售指导价  ZPRR：零售价格 – 基本车型）
     * @param codes 15位码/选装包编码
     * @return ApiResult
     */
    @Override
    public ApiResult queryPrice(String priceType, List<String> codes) {
        return ResponseUtil.ok(baseMapper.selectPrice(priceType, codes));
    }
}
